// ************************************************
// ACorns WCF Dynamic Client Proxy
// Copyright 2007 (C) ACorns Trading (www.acorns.com.au) (Corneliu I. Tusnea)
// corneliu@acorns.com.au
// http://www.acorns.com.au/blog/?p=142
// This package is provided "AS IS," without express or implied warranty of any kind, and may be used and modified.
// This package may be used in corporate applications without any pretence.
// Please keep this note
// ************************************************


using System;
using ACorns.WCF.DynamicClientProxy.Internal;
#if CONNECTION_POOL
using ACorns.WCF.DynamicClientProxy.Pool;
#endif

namespace ACorns.WCF.DynamicClientProxy
{
	/// <summary>
	/// Dynamic generator for a WCF ClientBase proxies
	/// </summary>
	/// <typeparam name="TInterface">The Type of Service Contract on which you want to build a Dynamic Client Proxy</typeparam>
	public static class WCFClientProxy<TInterface> where TInterface : class
	{
		/// <summary>
		/// Returns a new instance for a client proxy over the specified interface with the specified config name used for initialization.
		/// This is a simple instance of a ClientBase derived class.
		/// </summary>
		public static TInterface GetInstance(string configName)
		{
#if CONNECTION_POOL
			TInterface pooledInstance = ProxyConnectionPool.RequestFromPool<TInterface>();

			if ( pooledInstance != null )
				return pooledInstance;
#endif

			// Build the type
			Type type = ProxyBuilder.BuildType<TInterface, WCFProxyClassBuilder<TInterface>>();

			// Create new instance
			TInterface instance = (TInterface) Activator.CreateInstance(type, new object[] {configName});

#if CONNECTION_POOL
			ProxyConnectionPool.Register(instance);
#endif
			return instance;
		}

		/// <summary>
		/// Returns the type of class that represents a proxy over the specified interface with the specified config name used for initialization.
		/// This is a simple instance of a ClientBase derived class.
		/// </summary>
		public static Type GetInstanceType()
		{
			// Build the type
			Type type = ProxyBuilder.BuildType<TInterface, WCFProxyClassBuilder<TInterface>>();

			return type;
		}

		/// <summary>
		/// Returns a new instance for a client proxy over the specified interface with the specified config name used for initialization.
		/// This instance of the proxy can be reused as it will always "clean" itself
		/// if the channel is faulted.
		/// </summary>
		public static TInterface GetReusableInstance(string configName)
		{
#if CONNECTION_POOL
			TInterface pooledInstance = ProxyConnectionPool.RequestFromPool<TInterface>();

			if (pooledInstance != null)
				return pooledInstance;
#endif
			// Build the type
			Type type = ProxyBuilder.BuildType<TInterface, WCFReusableProxyClassBuilder<TInterface>>();

			// Create new instance
			TInterface instance = (TInterface) Activator.CreateInstance(type, new object[] {configName});

#if CONNECTION_POOL
			ProxyConnectionPool.Register(instance);
#endif
			return instance;
		}

		private static Type _reusableFaultUnwrappingInstance;

		/// <summary>
		/// Returns a new instance for a client proxy over the specified interface with the specified config name used for initialization.
		/// This instance of the proxy can be reused as it will always "clean" itself
		/// if the channel is faulted.
		/// The class will also unwrap any FaultException and throw the original Exception.
		/// </summary>
		public static TInterface GetReusableFaultUnwrappingInstance(string configName)
		{
#if CONNECTION_POOL
			TInterface pooledInstance = ProxyConnectionPool.RequestFromPool<TInterface>();

			if (pooledInstance != null)
				return pooledInstance;
#endif

			if (_reusableFaultUnwrappingInstance == null)
			{
				// no need to lock as the ProxyBuilder is thread safe and will always return the same stuff
				// Build the type
				_reusableFaultUnwrappingInstance = ProxyBuilder.BuildType<TInterface, WCFReusableFaultWrapperProxyClassBuilder<TInterface>>();
			}

			// Create new instance
			TInterface instance = (TInterface) Activator.CreateInstance(_reusableFaultUnwrappingInstance, new object[] {configName});

#if CONNECTION_POOL
			ProxyConnectionPool.Register(instance);
#endif
			return instance;
		}

		///// <summary>
		///// Returns a new instance for a client proxy over the specified interface with the specified config name used for initialization.
		///// </summary>
		//public static TInterface GetPolicyInstance(string configName)
		//{
		//    // Create new instance
		//    TInterface instance = GetReusableInstance(configName);

		//    return PolicyInjection.Wrap<TInterface>(instance);
		//}
	}
}